

#ifndef _TTG_DEVICES_GPU_CUDA_CUDAMANAGER_
#define _TTG_DEVICES_GPU_CUDA_CUDAMANAGER_
#include "Common/Definitions.h"

#include "Runtime.Low/Threads.h"
#include "CudaThread.h"
#include "CudaProps.h"

namespace ttg_internal
{
	namespace devices
	{
		//Detects Cuda Toolkit and scans for available Cuda-devices.
		//Manages cuda devices by creating associated threads and delegating tasks to them.
		class CudaManager
		{
			private:
				ttg::threads::FastCriticalSection locker;
				std::vector<std::pair<ttg::devices::CudaProps *,
									  CudaThread *>> cuda_devices;
				//Retuns potential dll-files.
				static std::vector<std::string> getCudaDlls();
				//Releases cuda device.
				//Note: it should be called in "locker" section.
				void releaseCudaDevices();
				//Inits manager.
				//Note: service "DllLoader" should be started!
				void init(bool);
			public:
				//Creates instance, that scans system and creates workers for each Cuda-device.
				CudaManager();
				//Returns count of available cuda devices.
				inline size_t getCount()
				{ return cuda_devices.size(); }
				//Returns properties for n-th cuda device.
				inline ttg::devices::CudaProps &getProps(size_t n)
				{ return *cuda_devices[n].first; }
				//Returns performer thread, that is assigned to n-th cuda device.
				inline CudaThread *getThread(size_t n)
				{ return cuda_devices[n].second; }
				//Performs requred action in the free CUDA-contexted thread (on corresponded CUDA device).
				//Note: "action" will be deleted.
				void perform(ttg::structures::InvokableObject *action);
				//Returns true, if cuda technology is available on current machine.
				inline bool isAvailable()
				{ return getCount() != 0; }
				//Terminates cuda-threads.
				~CudaManager();
		};
	};
};

#endif
